#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include "head.h"
/*   buzzer{
       buzzer=<gpiob 6 0>;
   };*/
/*   motor{
       motor=<gpiof 6 0>;
};*/
/*   fan{
       motor=<gpioe 9 0>;
};*/
unsigned int major;
struct class *cls;
struct device *dev;
struct device_node *dnode1; // 设备树节点对象 蜂鸣器
struct device_node *dnode2; // 设备树节点对象 马达
struct device_node *dnode3; // 设备树节点对象 风扇
struct gpio_desc *gpiono1;  // gpio对象 蜂鸣器
struct gpio_desc *gpiono2;  // gpio对象 马达
struct gpio_desc *gpiono3;  // gpio对象 风扇

// 封装操作方法
int rda226_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long buzzer_motor_fan_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int count,ret;
    ret = copy_from_user(&count, (void *)arg, 4);
    if (ret)
    {
        printk("copy_from_user fail\n");
        return -EIO;
    }

    //if(count >= 1 && count < 2)
    if(count == 1 )
        gpiod_set_value(gpiono1,1);  //蜂鸣器
    else if(count == 2)
    {
        gpiod_set_value(gpiono1,1);  //蜂鸣器
        gpiod_set_value(gpiono2,1);  //马达
    }else if(count >= 3)
    {
        gpiod_set_value(gpiono3,1);  //风扇
        gpiod_set_value(gpiono2,1);  //马达
        gpiod_set_value(gpiono1,1);  //蜂鸣器
    }

    return 0;
}

int rda226_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 定义操作方法结构体遍历并且初始化
struct file_operations fops = {
    .open = rda226_open,
    .unlocked_ioctl = buzzer_motor_fan_ioctl,
    .release = rda226_close,
};

static int __init mycdev_init(void)
{
    int ret;
    // 字符设备驱动注册
    major = register_chrdev(0, "buzzer_motor_fan", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        ret = major;
        goto out1;
    }
    printk("注册字符设备驱动成功\n");

    // 设备节点的创建
    // 向上提交目录
    cls = class_create(THIS_MODULE, "buzzer_motor_fan");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = PTR_ERR(cls);
        goto out2;
    }
    printk("向上提交目录成功\n");

    // 向上提交设备节点
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "buzzer_motor_fan");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点信息失败\n");
        ret = PTR_ERR(dev);
        goto out3;
    }
    printk("向上提交设备节点信息成功\n");

    // 解析蜂鸣器设备树节点
    dnode1 = of_find_node_by_name(NULL,"buzzer");
    if (dnode1 == NULL)
    {
        printk("解析蜂鸣器设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析蜂鸣器设备树节点成功\n");

    // 解析马达设备树节点
    dnode2 = of_find_node_by_name(NULL,"motor");
    if (dnode2 == NULL)
    {
        printk("解析马达设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析马达设备树节点成功\n");

    // 解析风扇设备树节点
    dnode3 = of_find_node_by_name(NULL,"fan");
    if (dnode3 == NULL)
    {
        printk("解析风扇设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析风扇设备树节点成功\n");

    // 申请gpio对象 蜂鸣器
    gpiono1 = gpiod_get_from_of_node(dnode1, "buzzer", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono1))
    {
        printk("申请蜂鸣器gpio对象失败\n");
        return -ENXIO;
    }
    printk("申请蜂鸣器gpio信息对象成功\n");

    // 申请gpio对象 马达
    gpiono2 = gpiod_get_from_of_node(dnode2, "motor", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono2))
    {
        printk("申请马达gpio对象失败\n");
        return -ENXIO;
    }
    printk("申请马达gpio信息对象成功\n");

    // 申请gpio对象 风扇
    gpiono3 = gpiod_get_from_of_node(dnode3, "fan", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono3))
    {
        printk("申请风扇gpio对象失败\n");
        return -ENXIO;
    }
    printk("申请风扇gpio信息对象成功\n");

    return 0;
out3:
    class_destroy(cls);
out2:
    unregister_chrdev(major, "buzzer_motor_fan");
out1:
    return ret;
}

static void __exit mycdev_exit(void)
{
    // 释放gpio对象
    gpiod_put(gpiono1);
    gpiod_put(gpiono2);
    gpiod_put(gpiono3);

    // 设备节点的销毁
    device_destroy(cls, MKDEV(major, 0));
    // 设备信息的注销
    class_destroy(cls);
    // 字符设备驱动注销
    unregister_chrdev(major, "buzzer_motorf_fan");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");